﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using PmSoft.DBContext;

namespace MQTTServer
{
	/// <summary>
	/// 服务访问器
	/// </summary>
	public class ServiceAccessor
	{
		private static IHttpContextAccessor? _httpContextAccessor;
		private static IServiceProvider? _rootServices;

		public static void Setup(IServiceProvider serviceProvider)
		{
			if (serviceProvider == null)
				throw new ArgumentNullException(nameof(serviceProvider));
			_rootServices = serviceProvider;
			_httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
		}

		/// <summary>
		/// 获取顶级服务提供器
		/// </summary>
		/// <returns></returns>
		public static IServiceProvider GetRootServices()
		{
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));
			return _rootServices;
		}

		/// <summary>
		/// 获取单实例
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <returns></returns>
		public static TService GetSingleton<TService>()
		{
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));
			var service = _rootServices.GetService<TService>();
			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取单实例
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <param name="type"></param>
		/// <returns></returns>
		public static TService GetSingleton<TService>(Type type) where TService : class
		{
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));
			var service = _rootServices.GetService(type) as TService;
			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取生命周期实例
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <returns></returns>
		public static TService GetScoped<TService>()
		{
			if (_httpContextAccessor == null)
				throw new ArgumentNullException(nameof(_httpContextAccessor));

			var service = _httpContextAccessor.HttpContext.RequestServices.GetService<TService>();
			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取生命周期实例
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <param name="type"></param>
		/// <returns></returns>
		public static TService GetScoped<TService>(Type type) where TService : class
		{
			if (_httpContextAccessor == null)
				throw new ArgumentNullException(nameof(_httpContextAccessor));

			var service = _httpContextAccessor.HttpContext.RequestServices.GetService(type) as TService;
			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取服务
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <returns></returns>
		public static TService GetService<TService>()
		{
			if (_httpContextAccessor == null)
				throw new ArgumentNullException(nameof(_httpContextAccessor));
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));

			var service = _httpContextAccessor.HttpContext == null ?
				_rootServices.GetService<TService>() :
				_httpContextAccessor.HttpContext.RequestServices.GetService<TService>();

			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取服务
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <param name="type"></param>
		/// <returns></returns>
		public static TService GetService<TService>(Type type) where TService : class
		{
			if (_httpContextAccessor == null)
				throw new ArgumentNullException(nameof(_httpContextAccessor));
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));

			var service = _httpContextAccessor.HttpContext == null ?
				_rootServices.GetService(type) as TService :
				_httpContextAccessor.HttpContext.RequestServices.GetService(type) as TService;

			if (service == null)
				throw new ArgumentNullException(nameof(service));
			return service;
		}

		/// <summary>
		/// 获取服务集合
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <returns></returns>
		public static IEnumerable<TService> GetServices<TService>()
		{
			if (_httpContextAccessor == null)
				throw new ArgumentNullException(nameof(_httpContextAccessor));
			if (_rootServices == null)
				throw new ArgumentNullException(nameof(_rootServices));

			return _httpContextAccessor.HttpContext == null ?
			   _rootServices.GetServices<TService>() :
			   _httpContextAccessor.HttpContext.RequestServices.GetServices<TService>();
		}


	}

}
